
#pragma once
#include "Connection.hpp"
#include "Epoller.hpp"
using namespace EpollModule;
#define MAX 1024 // 4096就poll出错
using connection_t = shared_ptr<Connection>;

// 最开始的时候，tcpserver只有一个listensockfd
class Reactor
{

    static const int event_num = 64;

private:
    bool IsConnectionExist(int sockfd)
    {
        return _connections.find(sockfd) != _connections.end();
    }

public:
    Reactor()
        : _epoller(make_unique<Epoller>()), // 注意先new出来否则空指针引用
          _isrunning(false)
    {
        _epoller->Init();
    }

    void EnabelReadWrite(int sockfd, bool readable, bool writeable)
    {
        // 修改用户层Connection的事件
        uint32_t events = ((readable ? EPOLLIN : 0)) | (writeable ? EPOLLOUT : 0);
        _connections[sockfd]->SetEvents(events);
        // 写透到内核中
        _epoller->Update(sockfd, events);
    }

    void InsertConnection(connection_t conn)
    {
        // 1.把连接放到哈希里管理
        LOG(LogLevel::DEBUG) << "conn:" << conn << "\n";
        auto iter = _connections.find(conn->Sockfd()); // 没有找到就插入进行管理
        if (iter == _connections.end())
        {
            _connections.insert(make_pair(conn->Sockfd(), conn)); // 插入哈希表管理
                                                                  // 2.把新插入的连接写透到内核的epoll中
            _epoller->Add(conn->Sockfd(), conn->GetEvents());
            // 3.上设置关联关系，让connection指向当前对象
            conn->SetOwner(this);
            LOG(LogLevel::DEBUG) << "Insert success , sockfd: " << conn->Sockfd() << "\n";
        }
    }

    void Dispatcher(int n)
    {
        for (int i = 0; i < n; i++)
        {
            // 开始进行派发给指定模块
            int sockfd = _revs[i].data.fd;
            uint16_t revents = _revs[i].events;
            if ((revents & EPOLLERR) || (revents & EPOLLHUP))
                revents = (EPOLLIN) | (EPOLLOUT);                 // 异常事件转化为读写事件
            if ((revents & EPOLLIN) && IsConnectionExist(sockfd)) // 读事件 && 连接存在
            {
                // _connections[sockfd]->CallRecv(); // 派发读事件
                LOG(LogLevel::DEBUG) << "Somebody Recver..." << i << " " << sockfd << " " << "\n";

                _connections[sockfd]->Recver(); // 注意这里是_connections[sockfd]
            }
            if ((revents & EPOLLOUT) && IsConnectionExist(sockfd)) // 读事件 && 连接存在
            {
                //_connections[sockfd]->CallSend(); // 派发写事件
                _connections[sockfd]->Sender();
            }
        }
    }

    void DebugPrint()
    {
        std::cout << "Epoller 管理的fd: ";
        for (auto &iter : _connections)
        {
            std::cout << iter.first << " ";
        }
        std::cout << std::endl;
    }

    void loopOnce(int timeout)
    {
        int n = _epoller->Wait(_revs, event_num, timeout); // 看有多少事件就绪
        Dispatcher(n);                                     // 事件派发
    }

    void loop()
    {
        _isrunning = true;
        int timeout = -1;
        LOG(LogLevel::DEBUG) << "before while...\n";
        while (_isrunning)
        {
            // LOG(LogLevel::DEBUG) << "before looponce...\n";
            loopOnce(timeout); // 超时管理
            DebugPrint();
        }
        _isrunning = false;
    }

    void DelConnection(int sockfd) // 关闭连接
    {
        // 1.从内核中移除对sockfd的关心
        _epoller->Delete(sockfd);
        // 2.关闭特定的文件描述符
        _connections[sockfd]->Close();
        // 3.哈希表中移除连接 不再进行管理
        _connections.erase(sockfd);
    }

    ~Reactor() {}

private:
    bool _isrunning;
    unique_ptr<Epoller> _epoller;                  // 注意一开始为nullptr
    unordered_map<int, connection_t> _connections; // 先描述再组织服务器内所有链接
    struct epoll_event _revs[event_num];           // 关心集合
};